/**
 * @file    gt98xx_drv_efc.h
 * @author  Giantec-Semi ATE
 * @brief   Header file of EFC driver module.
 * @version 0.1
 * 
 * @copyright Copyright (c) 2021 Giantec-Semi
 */

#ifndef GT98XX_DRIVERS_GT98XX_DRV_EFC_H_
#define GT98XX_DRIVERS_GT98XX_DRV_EFC_H_

#ifdef __cplusplus
  extern "C" {
#endif /* __cplusplus */

#include "gt98xx_drv_def.h"
#include "gt98xx_drv_conf.h"

/**
 * @addtogroup GT9881_Drivers
 * @{
 */

/**
 * @defgroup EFC_DRV EFC Drivers
 * @{
 */

/**
 * @defgroup EFC_DRV_Exported_Types EFC Drivers Exported Types
 * @{
 */
/**
 * @struct DrvEfcInitTypedef
 * @brief EFC drivers init structure definition
 */
typedef struct tagDrvEfcInitTypedef {
  uint32_t trw;                   ///< See @ref EFC_CFG0_TRW
  uint32_t trc;                   ///< See @ref EFC_CFG0_TRC
  uint32_t tprog;                 ///< See @ref EFC_CFG0_TPROG
  uint32_t sec;                   ///< See @ref EFC_CFG1_SEC
  uint32_t cec;                   ///< See @ref EFC_CFG2_CEC
  uint32_t tpgs;                  ///< See @ref EFC_CFG3_TPGS
  uint32_t tpgh;                  ///< See @ref EFC_CFG3_TPGH
  uint32_t tnvs;                  ///< See @ref EFC_CFG4_TNVS
  uint32_t trcv_prog;             ///< See @ref EFC_CFG4_TRCV_PROG
  uint32_t trcv_erase_sector;     ///< See @ref EFC_CFG5_TRCV_ERASE_SECTOR
  uint32_t trcv_erase_chip;       ///< See @ref EFC_CFG5_TRCV_ERASE_CHIP
  uint32_t twup;                  ///< See @ref EFC_CFG6_TWUP
} DrvEfcInitTypedef;
/** @} EFC_DRV_Exported_Types */

/**
 * @defgroup EFC_DRV_Exported_Constants EFC Drivers Exported Constants
 * @{
 */

/**
 * @enum  DrvEfcFlashArray
 * @brief Choose flash main array or NVR
 */
typedef enum tagDrvEfcFlashArray {
  kMain = 1,        ///< Flash main array
  kNvr = 0          ///< Flash NVR
} DrvEfcFlashArray;

/**
 * @enum  DrvEfcCmd
 * @brief Flash execution command
 */
typedef enum tagDrvEfcCmd {
  kProgram = 0,                       ///< Program
  kSectorErase = 0x555,               ///< Sector erase
  kChipErase = 0xAAA,                 ///< Chip erase
  kEnterDeepStandbyStatus = 0xA5A,    ///< Enter deep standby status
  kExitDeepStandbyStatus = 0x5A5      ///< Exit deep standby status
} DrvEfcCmd;

/**
 * @enum  DrvEfcLockArray
 * @brief Flash lock/unlock array
 */
typedef enum tagDrvEfcLockArray {
  kParmAndSectorProtectionReg = 1,  ///< Parameter reg & Sector protection reg
  kMainArrayAccess = 2,             ///< Main array access
  kNvrAccess = 4,                   ///< NVR access
  kErase = 8                        ///< ERASE
} DrvEfcLockArray;
/** @} EFC_DRV_Exported_Constants */

/**
 * @defgroup EFC_DRV_Exported_Functions EFC Drivers Exported Functions
 * @{
 */

/**
 * @defgroup EFC_DRV_EF_Configuration EFC Configuration Exported Functions
 * @{
 */

/**
 * @fn __STATIC_INLINE void DrvEfcChooseArray(EfcTypedef* efc_instance, DrvEfcFlashArray flash_array)
 * @brief Choose flash main array or NVR
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] flash_array Flash array
 */
__STATIC_INLINE void DrvEfcChooseArray(EfcTypedef* efc_instance, DrvEfcFlashArray flash_array) {
  MODIFY_REG(efc_instance->CTL, EFC_CTL_CENVR, flash_array);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEnableRetry(EfcTypedef* efc_instance)
 * @brief Enable flash retry operation
 * 
 * @param[in] efc_instance EFC instance
 */
__STATIC_INLINE void DrvEfcEnableRetry(EfcTypedef* efc_instance) {
  SET_BIT(efc_instance->CTL, EFC_CTL_RETRY);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableRetry(EfcTypedef* efc_instance)
 * @brief Disable flash retry operation
 * 
 * @param[in] efc_instance EFC instance
 */
__STATIC_INLINE void DrvEfcDisableRetry(EfcTypedef* efc_instance) {
  CLEAR_BIT(efc_instance->CTL, EFC_CTL_RETRY);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTrw(EfcTypedef* efc_instance, uint32_t trw)
 * @brief Set TRW(latency to next operation after program/erase).
 * @note The TRW = trw * Tclk_sys. Default : 8'd10.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] trw trw
 */
__STATIC_INLINE void DrvEfcSetTrw(EfcTypedef* efc_instance, uint32_t trw) {
  MODIFY_REG(efc_instance->CFG0, EFC_CFG0_TRW, trw << EFC_CFG0_TRW_Pos);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTrc(EfcTypedef* efc_instance, uint32_t trc)
 * @brief Set TRC(access time or initial access time for read).
 * @note TRC is used to define the wait cycles at the beginning of the read operation.
 * TRC = trc * Tclk_sys. Default : 8'd3.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] trc trc
 */
__STATIC_INLINE void DrvEfcSetTrc(EfcTypedef* efc_instance, uint32_t trc) {
  MODIFY_REG(efc_instance->CFG0, EFC_CFG0_TRC, trc << EFC_CFG0_TRC_Pos);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTprog(EfcTypedef* efc_instance, uint32_t tprog)
 * @brief Set TPROG(access time for physical write).
 * @note TPROG is used to define the wait cycles at the beginning of the physical write operation.
 * TPROG = tprog * Tclk_sys. Defalt : 16'd700.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] tprog tprog
 */
__STATIC_INLINE void DrvEfcSetTprog(EfcTypedef* efc_instance, uint32_t tprog) {
  MODIFY_REG(efc_instance->CFG0, EFC_CFG0_TPROG, tprog << EFC_CFG0_TPROG_Pos);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetSec(EfcTypedef* efc_instance, uint32_t sec)
 * @brief Set SEC(Sector Erase Cycle).
 * @note SEC = sec * Tclk_sys. Default : 32'd450000.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sec sec
 */
__STATIC_INLINE void DrvEfcSetSec(EfcTypedef* efc_instance, uint32_t sec) {
  WRITE_REG(efc_instance->CFG1, sec);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetCec(EfcTypedef* efc_instance, uint32_t cec)
 * @brief Set CEC(Chip Erase Cycle).
 * @note CEC = cec * Tclk_sys. Default : 32'd3000000.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] cec cec
 */
__STATIC_INLINE void DrvEfcSetCec(EfcTypedef* efc_instance, uint32_t cec) {
  WRITE_REG(efc_instance->CFG2, cec);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTpgs(EfcTypedef* efc_instance, uint32_t tpgs)
 * @brief Set TPGS(WEb low to PROG2 high Setup Time).
 * @note Default : 16'd600.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] tpgs TPGS
 */
__STATIC_INLINE void DrvEfcSetTpgs(EfcTypedef* efc_instance, uint32_t tpgs) {
  MODIFY_REG(efc_instance->CFG3, EFC_CFG3_TPGS, tpgs);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTpgh(EfcTypedef* efc_instance, uint32_t tpgh)
 * @brief Set TPGH(PROG2 Low to WEb high Hold Time).
 * @note Default : 16'd2.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] tpgh TPGH
 */
__STATIC_INLINE void DrvEfcSetTpgh(EfcTypedef* efc_instance, uint32_t tpgh) {
  MODIFY_REG(efc_instance->CFG3, EFC_CFG3_TPGH, tpgh << EFC_CFG3_TPGH_Pos);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTnvs(EfcTypedef* efc_instance, uint32_t tnvs)
 * @brief Set TNVS(PROG/ERASE/CEb/NVR/Address to WEb Setup Time).
 * @note Default : 16'd1000.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] tnvs TNVS
 */
__STATIC_INLINE void DrvEfcSetTnvs(EfcTypedef* efc_instance, uint32_t tnvs) {
  MODIFY_REG(efc_instance->CFG4, EFC_CFG4_TNVS, tnvs);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTrcvProg(EfcTypedef* efc_instance, uint32_t trcv_prog)
 * @brief Set TRCV_Prog.
 * @note Default : 16'd1000.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] trcv_prog TRCV_Prog
 */
__STATIC_INLINE void DrvEfcSetTrcvProg(EfcTypedef* efc_instance, uint32_t trcv_prog) {
  MODIFY_REG(efc_instance->CFG4, EFC_CFG4_TRCV_PROG, trcv_prog << EFC_CFG4_TRCV_PROG_Pos);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTrcvEraseSector(EfcTypedef* efc_instance, uint32_t trcv_erase_sector)
 * @brief Set Trcv erase sector.
 * @note Trcv erase sector is sector erase recover time. Default : 16'd10000.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] trcv_erase_sector Sector erase recover time
 */
__STATIC_INLINE void DrvEfcSetTrcvEraseSector(EfcTypedef* efc_instance, uint32_t trcv_erase_sector) {
  MODIFY_REG(efc_instance->CFG5, EFC_CFG5_TRCV_ERASE_SECTOR, trcv_erase_sector << EFC_CFG5_TRCV_ERASE_SECTOR_Pos);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTrcvEraseChip(EfcTypedef* efc_instance, uint32_t trcv_erase_chip)
 * @brief Set Trcv erase chip.
 * @note Trcv erase chip is chip erase recover time. Default : 16'd30000.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] trcv_erase_chip Chip erase recover time
 */
__STATIC_INLINE void DrvEfcSetTrcvEraseChip(EfcTypedef* efc_instance, uint32_t trcv_erase_chip) {
  MODIFY_REG(efc_instance->CFG5, EFC_CFG5_TRCV_ERASE_CHIP, trcv_erase_chip << EFC_CFG5_TRCV_ERASE_CHIP_Pos);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetTwup(EfcTypedef* efc_instance, uint32_t twup)
 * @brief Set Twup.
 * @note Twup is wakeup time from deep standby. Default : 16'd1000.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] twup Twup
 */
__STATIC_INLINE void DrvEfcSetTwup(EfcTypedef* efc_instance, uint32_t twup) {
  WRITE_REG(efc_instance->CFG6, twup);
}
/** @} EFC_DRV_EF_Configuration */

/**
 * @defgroup EFC_DRV_EF_Flag_Management EFC Flag Management Exported Functions
 * @{
 */

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcIsOpstActive(EfcTypedef* efc_instance)
 * @brief Check if the previous operation is finished.
 * 
 * @param[in] efc_instance EFC instance
 * @return Flash operation status.
 * @retval 0 The previous operation is not finished. Wait before further operation.
 * @retval 1 The previous operation is finished. Further operation can be applied.
 */
__STATIC_INLINE uint32_t DrvEfcIsOpstActive(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_OPST) >> EFC_STS0_OPST_Pos;
}

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcIsBusTransferErrorFlagActive(EfcTypedef* efc_instance)
 * @brief Check if a bus transfer error occurs.
 * 
 * @param[in] efc_instance EFC instance
 * @return Bus transfer error status
 * @retval 0 No error
 * @retval 1 Bus transfer error
 */
__STATIC_INLINE uint32_t DrvEfcIsBusTransferErrorFlagActive(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_BUSERR) >> EFC_STS0_BUSERR_Pos;
}

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcIsRegLock(EfcTypedef* efc_instance)
 * @brief Check if the registers access are locked.
 * 
 * @param[in] efc_instance EFC instance
 * @return The registers access status
 * @retval 0 EFC registers can be updated
 * @retval 1 EFC registers cannot be updated
 */
__STATIC_INLINE uint32_t DrvEfcIsRegLock(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_REG_LOCK) >> EFC_STS0_REG_LOCK_Pos;
}

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcIsMainArrayLocked(EfcTypedef* efc_instance)
 * @brief Check if main array could be write.
 * 
 * @param[in] efc_instance EFC instance
 * @return Main array writeable status
 * @retval 0 Main array can be updated
 * @retval 1 Main array cannot be updated
 */
__STATIC_INLINE uint32_t DrvEfcIsMainArrayLocked(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_MAINARRAY_LOCK) >> EFC_STS0_MAINARRAY_LOCK_Pos;
}

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcIsNvrLocked(EfcTypedef* efc_instance)
 * @brief Check if NVR coule be write.
 * 
 * @param[in] efc_instance EFC instance
 * @return NVR writeable status
 * @retval 0 NVR can be updated
 * @retval 1 NVR cannot be updated
 */
__STATIC_INLINE uint32_t DrvEfcIsNvrLocked(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_NVR_LOCK) >> EFC_STS0_NVR_LOCK_Pos;
}

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcIsEraseLocked(EfcTypedef* efc_instance)
 * @brief Check if erase operation is locked.
 * 
 * @param[in] efc_instance EFC instance
 * @return Erase operation status
 * @retval 0 Erase operation is not locked
 * @retval 1 Erase operation is locked
 */
__STATIC_INLINE uint32_t DrvEfcIsEraseLocked(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_EARSE_LOCK) >> EFC_STS0_EARSE_LOCK_Pos;
}

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcIsInitializationDone(EfcTypedef* efc_instance)
 * @brief Check if initialization is done.
 * 
 * @param[in] efc_instance EFC instance
 * @return Initialization status
 * @retval 0 Initialization is not done
 * @retval 1 Initialization is done
 */
__STATIC_INLINE uint32_t DrvEfcIsInitializationDone(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_INIT_STAT) >> EFC_STS0_INIT_STAT_Pos;
}

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcIsWriteAddressUnalignErrorActive(EfcTypedef* efc_instance)
 * @brief Check if write address unalign error occurs.
 * 
 * @param[in] efc_instance EFC instance
 * @return Write address unalign error status
 * @retval 0 No write address unalign error
 * @retval 1 Write address unalign error occurs
 */
__STATIC_INLINE uint32_t DrvEfcIsWriteAddressUnalignErrorActive(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_UNAERR) >> EFC_STS0_UNAERR_Pos;
}

/**
 * @fn __STATIC_INLINE uint32_t DrvEfcGetCurrentStatus(EfcTypedef* efc_instance)
 * @brief Get current status;
 * 
 * @param[in] efc_instance EFC instance
 * @return Current status
 * @retval 0 Idle
 * @retval 1 Read
 * @retval 2 Program
 * @retval 3 Sector erase
 * @retval 4 Chip erase
 * @retval 5 Enter DPSTB
 * @retval 6 Exit DPSTB
 */
__STATIC_INLINE uint32_t DrvEfcGetCurrentStatus(EfcTypedef* efc_instance) {
  return READ_BIT(efc_instance->STS0, EFC_STS0_CURR_STAT) >> EFC_STS0_CURR_STAT_Pos;
}

/**
 * @fn __STATIC_INLINE void DrvEfcClearError(EfcTypedef* efc_instance)
 * @brief Clear STS0.BUSERR and STS0.UNAERR.
 * 
 * @param[in] efc_instance 
 */
__STATIC_INLINE void DrvEfcClearError(EfcTypedef* efc_instance) {
  WRITE_REG(efc_instance->ERR_CLR, 1);
}
/** @} EFC_DRV_EF_Flag_Management */

/**
 * @defgroup EFC_DRV_EF_Erase EFC Erase Exported Functions
 * @{
 */

/**
 * @fn __STATIC_INLINE void DrvEfcAllowEraseMainArray(EfcTypedef* efc_instance)
 * @brief Allow erase of main array
 * @note Write @ref kEraseCmdKeyMainArray to @ref EfcTypedef::ERASE_CMD_KEY to allow erase
 * of main array.
 * 
 * @param[in] efc_instance EFC instance
 */
__STATIC_INLINE void DrvEfcAllowEraseMainArray(EfcTypedef* efc_instance) {
  WRITE_REG(efc_instance->ERASE_CMD_KEY, kEraseCmdKeyMainArray);
}

/**
 * @fn __STATIC_INLINE void DrvEfcAllowEraseTrim3Sector(EfcTypedef* efc_instance)
 * @brief Allow erase of Trim3 Sector
 * @note Write @ref kEraseCmdKeyTrim3 to @ref EfcTypedef::ERASE_CMD_KEY to allow erase
 * of Trim3 Sector.
 * 
 * @param[in] efc_instance EFC instance
 */
__STATIC_INLINE void DrvEfcAllowEraseTrim3Sector(EfcTypedef* efc_instance) {
  WRITE_REG(efc_instance->ERASE_CMD_KEY, kEraseCmdKeyTrim3);
}

/**
 * @fn __STATIC_INLINE void DrvEfcAllowEraseTrim2Sector(EfcTypedef* efc_instance)
 * @brief Allow erase of Trim2 Sector
 * @note Write @ref kEraseCmdKeyTrim2 to @ref EfcTypedef::ERASE_CMD_KEY to allow erase
 * of Trim2 Sector.
 * 
 * @param[in] efc_instance EFC instance
 */
__STATIC_INLINE void DrvEfcAllowEraseTrim2Sector(EfcTypedef* efc_instance) {
  WRITE_REG(efc_instance->ERASE_CMD_KEY, kEraseCmdKeyTrim2);
}

/**
 * @fn __STATIC_INLINE void DrvEfcAllowEraseTrim1Sector(EfcTypedef* efc_instance)
 * @brief Allow erase of Trim1 Sector
 * @note Write @ref kEraseCmdKeyTrim1 to @ref EfcTypedef::ERASE_CMD_KEY to allow erase
 * of Trim1 Sector.
 * 
 * @param[in] efc_instance EFC instance
 */
__STATIC_INLINE void DrvEfcAllowEraseTrim1Sector(EfcTypedef* efc_instance) {
  WRITE_REG(efc_instance->ERASE_CMD_KEY, kEraseCmdKeyTrim1);
}

/**
 * @fn __STATIC_INLINE void DrvEfcSetEraseSector(EfcTypedef* efc_instance, uint32_t addr)
 * @brief Set address of sector to be erased.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] addr Address of sector to hold
 */
__STATIC_INLINE void DrvEfcSetEraseSector(EfcTypedef* efc_instance, uint32_t addr) {
  WRITE_REG(efc_instance->ERASE_ADDR, addr);
}
/** @} EFC_DRV_EF_Erase */

/**
 * @defgroup EFC_DRV_EF_Sector_Protection EFC Sector Protection Exported Functions
 * @{
 */

/**
 * @fn __STATIC_INLINE void DrvEfcEnableSector1To32Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Enable main array section access of sector1~32.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to enable.
 * <pre>
 * Bit0 : Sector 01
 * Bit1 : Sector 02
 * ...
 * Bit 31 : Sector 32
 * </pre>
 */
__STATIC_INLINE void DrvEfcEnableSector1To32Access(EfcTypedef* efc_instance, uint32_t sectors) {
  SET_BIT(efc_instance->SEC_PROT0, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableSector1To32Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Disable main array section access of sector1~32.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to disable.
 * <pre>
 * Bit0 : Sector 01
 * Bit1 : Sector 02
 * ...
 * Bit 31 : Sector 32
 * </pre>
 */
__STATIC_INLINE void DrvEfcDisableSector1To32Access(EfcTypedef* efc_instance, uint32_t sectors) {
  CLEAR_BIT(efc_instance->SEC_PROT0, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEnableSector33To64Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Enable main array section access of sector33~64.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to enable.
 * <pre>
 * Bit0 : Sector 33
 * Bit1 : Sector 34
 * ...
 * Bit 31 : Sector 64
 * </pre>
 */
__STATIC_INLINE void DrvEfcEnableSector33To64Access(EfcTypedef* efc_instance, uint32_t sectors) {
  SET_BIT(efc_instance->SEC_PROT1, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableSector33To64Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Disable main array section access of sector33~64.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to disable.
 * <pre>
 * Bit0 : Sector 33
 * Bit1 : Sector 34
 * ...
 * Bit 31 : Sector 64
 * </pre>
 */
__STATIC_INLINE void DrvEfcDisableSector33To64Access(EfcTypedef* efc_instance, uint32_t sectors) {
  CLEAR_BIT(efc_instance->SEC_PROT1, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEnableSector65To96Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Enable main array section access of sector65~96.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to enable.
 * <pre>
 * Bit0 : Sector 65
 * Bit1 : Sector 66
 * ...
 * Bit 31 : Sector 96
 * </pre>
 */
__STATIC_INLINE void DrvEfcEnableSector65To96Access(EfcTypedef* efc_instance, uint32_t sectors) {
  SET_BIT(efc_instance->SEC_PROT2, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableSector65To96Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Disable main array section access of sector65~96.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to disable.
 * <pre>
 * Bit0 : Sector 65
 * Bit1 : Sector 66
 * ...
 * Bit 31 : Sector 96
 * </pre>
 */
__STATIC_INLINE void DrvEfcDisableSector65To96Access(EfcTypedef* efc_instance, uint32_t sectors) {
  CLEAR_BIT(efc_instance->SEC_PROT2, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEnableSector97To128Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Enable main array section access of sector97~128.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to enable.
 * <pre>
 * Bit0 : Sector 97
 * Bit1 : Sector 98
 * ...
 * Bit 31 : Sector 128
 * </pre>
 */
__STATIC_INLINE void DrvEfcEnableSector97To128Access(EfcTypedef* efc_instance, uint32_t sectors) {
  SET_BIT(efc_instance->SEC_PROT3, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableSector97To128Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Disable main array section access of sector97~128.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to disable.
 * <pre>
 * Bit0 : Sector 97
 * Bit1 : Sector 98
 * ...
 * Bit 31 : Sector 128
 * </pre>
 */
__STATIC_INLINE void DrvEfcDisableSector97To128Access(EfcTypedef* efc_instance, uint32_t sectors) {
  CLEAR_BIT(efc_instance->SEC_PROT3, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEnableSector129To160Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Enable main array section access of sector129~160.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to enable.
 * <pre>
 * Bit0 : Sector 129
 * Bit1 : Sector 130
 * ...
 * Bit 31 : Sector 160
 * </pre>
 */
__STATIC_INLINE void DrvEfcEnableSector129To160Access(EfcTypedef* efc_instance, uint32_t sectors) {
  SET_BIT(efc_instance->SEC_PROT4, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableSector129To160Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Disable main array section access of sector129~160.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to disable.
 * <pre>
 * Bit0 : Sector 129
 * Bit1 : Sector 130
 * ...
 * Bit 31 : Sector 160
 * </pre>
 */
__STATIC_INLINE void DrvEfcDisableSector129To160Access(EfcTypedef* efc_instance, uint32_t sectors) {
  CLEAR_BIT(efc_instance->SEC_PROT4, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEnableSector161To192Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Enable main array section access of sector161~192.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to enable.
 * <pre>
 * Bit0 : Sector 161
 * Bit1 : Sector 162
 * ...
 * Bit 31 : Sector 192
 * </pre>
 */
__STATIC_INLINE void DrvEfcEnableSector161To192Access(EfcTypedef* efc_instance, uint32_t sectors) {
  SET_BIT(efc_instance->SEC_PROT5, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableSector161To192Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Disable main array section access of sector161~192.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to disable.
 * <pre>
 * Bit0 : Sector 161
 * Bit1 : Sector 162
 * ...
 * Bit 31 : Sector 192
 * </pre>
 */
__STATIC_INLINE void DrvEfcDisableSector161To192Access(EfcTypedef* efc_instance, uint32_t sectors) {
  CLEAR_BIT(efc_instance->SEC_PROT5, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEnableSector193To224Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Enable main array section access of sector193~224.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to enable.
 * <pre>
 * Bit0 : Sector 193
 * Bit1 : Sector 194
 * ...
 * Bit 31 : Sector 224
 * </pre>
 */
__STATIC_INLINE void DrvEfcEnableSector193To224Access(EfcTypedef* efc_instance, uint32_t sectors) {
  SET_BIT(efc_instance->SEC_PROT6, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableSector193To224Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Disable main array section access of sector193~224.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to disable.
 * <pre>
 * Bit0 : Sector 193
 * Bit1 : Sector 194
 * ...
 * Bit 31 : Sector 224
 * </pre>
 */
__STATIC_INLINE void DrvEfcDisableSector193To224Access(EfcTypedef* efc_instance, uint32_t sectors) {
  CLEAR_BIT(efc_instance->SEC_PROT6, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEnableSector225To256Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Enable main array section access of sector225~256.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to enable.
 * <pre>
 * Bit0 : Sector 225
 * Bit1 : Sector 226
 * ...
 * Bit 31 : Sector 256
 * </pre>
 */
__STATIC_INLINE void DrvEfcEnableSector225To256Access(EfcTypedef* efc_instance, uint32_t sectors) {
  SET_BIT(efc_instance->SEC_PROT7, sectors);
}

/**
 * @fn __STATIC_INLINE void DrvEfcDisableSector225To256Access(EfcTypedef* efc_instance, uint32_t sectors)
 * @brief Disable main array section access of sector225~256.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sectors Each bit represents a sector to disable.
 * <pre>
 * Bit0 : Sector 225
 * Bit1 : Sector 226
 * ...
 * Bit 31 : Sector 256
 * </pre>
 */
__STATIC_INLINE void DrvEfcDisableSector225To256Access(EfcTypedef* efc_instance, uint32_t sectors) {
  CLEAR_BIT(efc_instance->SEC_PROT7, sectors);
}
/** @} EFC_DRV_EF_Sector_Protection */

/**
 * @defgroup EFC_DRV_EF_Init EFC Initialization Exported Functions
 * @{
 */

/**
 * @fn void DrvEfcStructInit(DrvEfcInitTypedef* efc_init_struct)
 * @brief Set each @ref DrvEfcInitTypedef field to default value.
 * 
 * @param[out] efc_init_struct Pointer to a @ref DrvEfcInitTypedef structure
 *             which field will be set to default values.
 */
void DrvEfcStructInit(DrvEfcInitTypedef* efc_init_struct);

/**
 * @fn ErrorStatus void DrvEfcInit(EfcTypedef* efc_instance, DrvEfcInitTypedef* efc_init_struct)
 * @brief Initialize EFC registers according to the specified parameters in efc_init_struct.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] efc_init_struct Pointer to a @ref DrvEfcInitTypedef structure which contains the 
 *            configuration information of EFC.
 * @return EFC is initialized or not
 * @retval kSuccess EFC registers are initialized according to efc_init_struct
 * @retval kError Error occured during EFC registers initialization
 */
ErrorStatus DrvEfcInit(EfcTypedef* efc_instance, DrvEfcInitTypedef* efc_init_struct);

/** @} EFC_DRV_EF_Init */

/**
 * @defgroup EFC_DRV_EF_Operation EFC Operation Exported Functions
 * @{
 */
/**
 * @fn __STATIC_INLINE void DrvEfcExecute(EfcTypedef* efc_instance, DrvEfcCmd cmd)
 * @brief Execute flash command.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] cmd Flash execution command. Could be one of the following values:
 *                @arg @ref kProgram                  Program
 *                @arg @ref kSectorErase              Sector Erase
 *                @arg @ref kChipErase                Chip Erase
 *                @arg @ref kEnterDeepStandbyStatus   Enter deep standby status
 *                @arg @ref kExitDeepStandbyStatus    Exit deep standby status
 */
__STATIC_INLINE void DrvEfcExecute(EfcTypedef* efc_instance, DrvEfcCmd cmd) {
  WRITE_REG(efc_instance->CMD, cmd);
}

/**
 * @fn __STATIC_INLINE void DrvEfcLock(EfcTypedef* efc_instance, uint32_t lock_array)
 * @brief Lock parameter update/main array/nvr/erase operation.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] lock_array Lock array. See @ref DrvEfcLockArray.
 */
__STATIC_INLINE void DrvEfcLock(EfcTypedef* efc_instance, uint32_t lock_array) {
  SET_BIT(efc_instance->LOCK, lock_array);
}

/**
 * @fn __STATIC_INLINE void DrvEfcUnlock(EfcTypedef* efc_instance, uint32_t unlock_array)
 * @brief Unlock parameter update/main array/nvr/erase operation.
 * 
 * @param efc_instance EFC instance
 * @param unlock_array Unlock array. See @ref DrvEfcLockArray
 */
__STATIC_INLINE void DrvEfcUnlock(EfcTypedef* efc_instance, uint32_t unlock_array) {
  CLEAR_BIT(efc_instance->LOCK, unlock_array);
}

/**
 * @fn __STATIC_INLINE void DrvEfcEraseChip(EfcTypedef* efc_instance)
 * @brief Erase chip.
 * 
 * @param[in] efc_instance EFC instance;
 */
__STATIC_INLINE void DrvEfcEraseChip(EfcTypedef* efc_instance) {
  DrvEfcAllowEraseMainArray(efc_instance);
  DrvEfcSetEraseSector(efc_instance, 0);
  DrvEfcExecute(efc_instance, kChipErase);
  while (!DrvEfcIsOpstActive(efc_instance)) {}
}

/**
 * @fn __STATIC_INLINE void DrvEfcEraseSector(EfcTypedef* efc_instance, uint32_t sector)
 * @brief Erase sector.
 * 
 * @param[in] efc_instance EFC instance
 * @param[in] sector Sector addr
 */
__STATIC_INLINE void DrvEfcEraseSector(EfcTypedef* efc_instance, uint32_t sector) {
  DrvEfcAllowEraseMainArray(efc_instance);
  DrvEfcSetEraseSector(efc_instance, sector);
  DrvEfcExecute(efc_instance, kSectorErase);
  while (!DrvEfcIsOpstActive(efc_instance)) {}
}

/**
 * @fn __STATIC_INLINE void DrvEfcPreProgram(EfcTypedef* efc_instance)
 * @brief Prepare for flash programing. Clear @ref EFC_ERASE_CMD_KEY and @ref EFC_CMD
 * 
 * @param efc_instance EFC instance
 */
__STATIC_INLINE void DrvEfcPreProgram(EfcTypedef* efc_instance) {
  WRITE_REG(efc_instance->ERASE_CMD_KEY, 0);
  DrvEfcExecute(efc_instance, kProgram);
}
/** @} EFC_DRV_EF_Operation */

/** @} EFC_DRV_Exported_Functions */
/** @} EFC_DRV */
/** @} GT9881_Drivers */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* GT98XX_DRIVERS_GT98XX_DRV_EFC_H_ */
